@@ -56,7 +56,7 @@  | 
            ||
| 56 | 56 | 
                 		05130FDB21CA1AE0004EF1BE /* ScanQRViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAD71E70047E0006FEE0 /* ScanQRViewController.swift */; };
               | 
            
| 57 | 57 | 
                 		05130FDD21CA1B04004EF1BE /* GroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAB1E7004700006FEE0 /* GroupViewController.swift */; };
               | 
            
| 58 | 58 | 
                 		05130FDF21CA1B04004EF1BE /* MemberCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB61E7004700006FEE0 /* MemberCell.swift */; };
               | 
            
| 59 | 
                -		05130FE021CA1B04004EF1BE /* GroupDetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB11E7004700006FEE0 /* GroupDetailController.swift */; };
               | 
            |
| 59 | 
                +		05130FE021CA1B04004EF1BE /* GroupDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */; };
               | 
            |
| 60 | 60 | 
                 		05130FE121CA1B04004EF1BE /* GroupMemberController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */; };
               | 
            
| 61 | 61 | 
                 		05130FE221CA1B04004EF1BE /* ChangeGroupNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */; };
               | 
            
| 62 | 62 | 
                 		05130FE321CA1B04004EF1BE /* ShowGroupQRController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69FFAB71E7004700006FEE0 /* ShowGroupQRController.swift */; };
               | 
            
                @@ -91,7 +91,6 @@  | 
            ||
| 91 | 91 | 
                 		0513100721CA1B39004EF1BE /* UIViewController+UIBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6CCC0581E793DD0004BCC9D /* UIViewController+UIBarButtonItem.swift */; };
               | 
            
| 92 | 92 | 
                 		0513100A21CA1B39004EF1BE /* UIBarButtonItemExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543272E21C68C1900C6388D /* UIBarButtonItemExt.swift */; };
               | 
            
| 93 | 93 | 
                 		0513100B21CA1B39004EF1BE /* UIColorExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543272F21C68C1900C6388D /* UIColorExt.swift */; };
               | 
            
| 94 | 
                -		0513100E21CA1B39004EF1BE /* UIButtonExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543273221C68C1900C6388D /* UIButtonExt.swift */; };
               | 
            |
| 95 | 94 | 
                 		0513100F21CA1B39004EF1BE /* UIViewExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543273321C68C1900C6388D /* UIViewExt.swift */; };
               | 
            
| 96 | 95 | 
                 		0513101021CA1B39004EF1BE /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543273421C68C1900C6388D /* UIViewControllerExt.swift */; };
               | 
            
| 97 | 96 | 
                 		0513101221CA1B39004EF1BE /* UITextFieldExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543273621C68C1900C6388D /* UITextFieldExt.swift */; };
               | 
            
                @@ -184,9 +183,6 @@  | 
            ||
| 184 | 183 | 
                 		052BF1C921E344280010D270 /* PullToRefresh.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052BF1C721E344020010D270 /* PullToRefresh.framework */; };
               | 
            
| 185 | 184 | 
                 		0535D6D921D32A89008D9403 /* WXUserInfoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0535D6D821D32A89008D9403 /* WXUserInfoRemoteAPI.swift */; };
               | 
            
| 186 | 185 | 
                 		0535D6DB21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0535D6DA21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift */; };
               | 
            
| 187 | 
                -		053E125F21F16BA400A64893 /* ToastTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E125E21F16BA400A64893 /* ToastTextView.swift */; };
               | 
            |
| 188 | 
                -		053E126121F16BB100A64893 /* ToastImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126021F16BB100A64893 /* ToastImageView.swift */; };
               | 
            |
| 189 | 
                -		053E126321F16EF300A64893 /* ToastContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126221F16EF300A64893 /* ToastContentView.swift */; };
               | 
            |
| 190 | 186 | 
                 		053E126521F1718E00A64893 /* PageOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126421F1718E00A64893 /* PageOption.swift */; };
               | 
            
| 191 | 187 | 
                 		053E126721F1719F00A64893 /* PageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126621F1719F00A64893 /* PageItem.swift */; };
               | 
            
| 192 | 188 | 
                 		053E126921F171C500A64893 /* ToastOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E126821F171C500A64893 /* ToastOption.swift */; };
               | 
            
                @@ -200,6 +196,9 @@  | 
            ||
| 200 | 196 | 
                 		0543E80B21D1DF4000A42807 /* GroupMemberItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80A21D1DF4000A42807 /* GroupMemberItem.swift */; };
               | 
            
| 201 | 197 | 
                 		0543E80D21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80C21D1E2EA00A42807 /* PhotoGroupDetailRepository.swift */; };
               | 
            
| 202 | 198 | 
                 		0543E80F21D1FD1100A42807 /* GroupDetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0543E80E21D1FD1100A42807 /* GroupDetailItem.swift */; };
               | 
            
| 199 | 
                +		055BB53E220AEA3B009548AA /* NiblessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055BB53D220AEA3B009548AA /* NiblessViewController.swift */; };
               | 
            |
| 200 | 
                +		055BB541220AEA62009548AA /* NiblessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055BB540220AEA62009548AA /* NiblessView.swift */; };
               | 
            |
| 201 | 
                +		055EFAD7221A4DB400450AD5 /* GroupQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055EFAD6221A4DB400450AD5 /* GroupQRView.swift */; };
               | 
            |
| 203 | 202 | 
                 		0569F6152200438C000A75CA /* Group.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0569F613220042AF000A75CA /* Group.storyboard */; };
               | 
            
| 204 | 203 | 
                 		0569F61822014B24000A75CA /* NavigationBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0569F61722014B24000A75CA /* NavigationBarDelegate.swift */; };
               | 
            
| 205 | 204 | 
                 		0569F61A22014B30000A75CA /* NavigationBarProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0569F61922014B30000A75CA /* NavigationBarProxy.swift */; };
               | 
            
                @@ -417,9 +416,6 @@  | 
            ||
| 417 | 416 | 
                 		052BF1C721E344020010D270 /* PullToRefresh.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PullToRefresh.framework; path = Carthage/Build/iOS/PullToRefresh.framework; sourceTree = "<group>"; };
               | 
            
| 418 | 417 | 
                 		0535D6D821D32A89008D9403 /* WXUserInfoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WXUserInfoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 419 | 418 | 
                 		0535D6DA21D32A9E008D9403 /* GuestUserInfoRemoteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestUserInfoRemoteAPI.swift; sourceTree = "<group>"; };
               | 
            
| 420 | 
                -		053E125E21F16BA400A64893 /* ToastTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastTextView.swift; sourceTree = "<group>"; };
               | 
            |
| 421 | 
                -		053E126021F16BB100A64893 /* ToastImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastImageView.swift; sourceTree = "<group>"; };
               | 
            |
| 422 | 
                -		053E126221F16EF300A64893 /* ToastContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastContentView.swift; sourceTree = "<group>"; };
               | 
            |
| 423 | 419 | 
                 		053E126421F1718E00A64893 /* PageOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageOption.swift; sourceTree = "<group>"; };
               | 
            
| 424 | 420 | 
                 		053E126621F1719F00A64893 /* PageItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageItem.swift; sourceTree = "<group>"; };
               | 
            
| 425 | 421 | 
                 		053E126821F171C500A64893 /* ToastOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastOption.swift; sourceTree = "<group>"; };
               | 
            
                @@ -435,7 +431,6 @@  | 
            ||
| 435 | 431 | 
                 		0543272A21C68C1900C6388D /* CGSizeExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGSizeExt.swift; sourceTree = "<group>"; };
               | 
            
| 436 | 432 | 
                 		0543272E21C68C1900C6388D /* UIBarButtonItemExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBarButtonItemExt.swift; sourceTree = "<group>"; };
               | 
            
| 437 | 433 | 
                 		0543272F21C68C1900C6388D /* UIColorExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColorExt.swift; sourceTree = "<group>"; };
               | 
            
| 438 | 
                -		0543273221C68C1900C6388D /* UIButtonExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExt.swift; sourceTree = "<group>"; };
               | 
            |
| 439 | 434 | 
                 		0543273321C68C1900C6388D /* UIViewExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewExt.swift; sourceTree = "<group>"; };
               | 
            
| 440 | 435 | 
                 		0543273421C68C1900C6388D /* UIViewControllerExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewControllerExt.swift; sourceTree = "<group>"; };
               | 
            
| 441 | 436 | 
                 		0543273621C68C1900C6388D /* UITextFieldExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextFieldExt.swift; sourceTree = "<group>"; };
               | 
            
                @@ -453,6 +448,9 @@  | 
            ||
| 453 | 448 | 
                 		05468AF11F8B73A000B8F469 /* PhotoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoItem.swift; sourceTree = "<group>"; };
               | 
            
| 454 | 449 | 
                 		054863661FA326CB00A39DA0 /* PhotoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCell.swift; sourceTree = "<group>"; };
               | 
            
| 455 | 450 | 
                 		054863671FA326CB00A39DA0 /* PhotoCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PhotoCell.xib; sourceTree = "<group>"; };
               | 
            
| 451 | 
                +		055BB53D220AEA3B009548AA /* NiblessViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NiblessViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 452 | 
                +		055BB540220AEA62009548AA /* NiblessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NiblessView.swift; sourceTree = "<group>"; };
               | 
            |
| 453 | 
                +		055EFAD6221A4DB400450AD5 /* GroupQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupQRView.swift; sourceTree = "<group>"; };
               | 
            |
| 456 | 454 | 
                 		0569F613220042AF000A75CA /* Group.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Group.storyboard; sourceTree = "<group>"; };
               | 
            
| 457 | 455 | 
                 		0569F61722014B24000A75CA /* NavigationBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarDelegate.swift; sourceTree = "<group>"; };
               | 
            
| 458 | 456 | 
                 		0569F61922014B30000A75CA /* NavigationBarProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarProxy.swift; sourceTree = "<group>"; };
               | 
            
                @@ -548,7 +546,7 @@  | 
            ||
| 548 | 546 | 
                 		A69FFAAC1E7004700006FEE0 /* GroupViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 549 | 547 | 
                 		A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeGroupNameController.swift; sourceTree = "<group>"; };
               | 
            
| 550 | 548 | 
                 		A69FFAB01E7004700006FEE0 /* GroupDetailModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailModel.swift; sourceTree = "<group>"; };
               | 
            
| 551 | 
                -		A69FFAB11E7004700006FEE0 /* GroupDetailController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailController.swift; sourceTree = "<group>"; };
               | 
            |
| 549 | 
                +		A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailViewController.swift; sourceTree = "<group>"; };
               | 
            |
| 552 | 550 | 
                 		A69FFAB21E7004700006FEE0 /* GroupDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupDetailViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 553 | 551 | 
                 		A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupMemberController.swift; sourceTree = "<group>"; };
               | 
            
| 554 | 552 | 
                 		A69FFAB61E7004700006FEE0 /* MemberCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemberCell.swift; sourceTree = "<group>"; };
               | 
            
                @@ -693,6 +691,7 @@  | 
            ||
| 693 | 691 | 
                 		05130F4D21C94B72004EF1BE /* UIKit */ = {
               | 
            
| 694 | 692 | 
                isa = PBXGroup;  | 
            
| 695 | 693 | 
                children = (  | 
            
| 694 | 
                + 055BB53F220AEA4E009548AA /* Nibless */,  | 
            |
| 696 | 695 | 
                0584FD7A21FABA0300FA1E3E /* Present */,  | 
            
| 697 | 696 | 
                0521145521F083FA0047C55A /* Toast */,  | 
            
| 698 | 697 | 
                05C8D21E21EDD5A80001E847 /* NavigationBar */,  | 
            
                @@ -927,9 +926,6 @@  | 
            ||
| 927 | 926 | 
                children = (  | 
            
| 928 | 927 | 
                053E126A21F5696E00A64893 /* Toast.swift */,  | 
            
| 929 | 928 | 
                0521145321F083F20047C55A /* ToastView.swift */,  | 
            
| 930 | 
                - 053E125E21F16BA400A64893 /* ToastTextView.swift */,  | 
            |
| 931 | 
                - 053E126021F16BB100A64893 /* ToastImageView.swift */,  | 
            |
| 932 | 
                - 053E126221F16EF300A64893 /* ToastContentView.swift */,  | 
            |
| 933 | 929 | 
                053E126821F171C500A64893 /* ToastOption.swift */,  | 
            
| 934 | 930 | 
                053E126C21F5767300A64893 /* ToastAnimator.swift */,  | 
            
| 935 | 931 | 
                053E126E21F5774700A64893 /* FadeToastAnimator.swift */,  | 
            
                @@ -996,7 +992,6 @@  | 
            ||
| 996 | 992 | 
                A6CCC0581E793DD0004BCC9D /* UIViewController+UIBarButtonItem.swift */,  | 
            
| 997 | 993 | 
                0543272E21C68C1900C6388D /* UIBarButtonItemExt.swift */,  | 
            
| 998 | 994 | 
                0543272F21C68C1900C6388D /* UIColorExt.swift */,  | 
            
| 999 | 
                - 0543273221C68C1900C6388D /* UIButtonExt.swift */,  | 
            |
| 1000 | 995 | 
                0543273321C68C1900C6388D /* UIViewExt.swift */,  | 
            
| 1001 | 996 | 
                0543273421C68C1900C6388D /* UIViewControllerExt.swift */,  | 
            
| 1002 | 997 | 
                0543273621C68C1900C6388D /* UITextFieldExt.swift */,  | 
            
                @@ -1054,6 +1049,15 @@  | 
            ||
| 1054 | 1049 | 
                path = PhotoDetail;  | 
            
| 1055 | 1050 | 
                sourceTree = "<group>";  | 
            
| 1056 | 1051 | 
                };  | 
            
| 1052 | 
                +		055BB53F220AEA4E009548AA /* Nibless */ = {
               | 
            |
| 1053 | 
                + isa = PBXGroup;  | 
            |
| 1054 | 
                + children = (  | 
            |
| 1055 | 
                + 055BB53D220AEA3B009548AA /* NiblessViewController.swift */,  | 
            |
| 1056 | 
                + 055BB540220AEA62009548AA /* NiblessView.swift */,  | 
            |
| 1057 | 
                + );  | 
            |
| 1058 | 
                + path = Nibless;  | 
            |
| 1059 | 
                + sourceTree = "<group>";  | 
            |
| 1060 | 
                + };  | 
            |
| 1057 | 1061 | 
                 		0569F61622014AF9000A75CA /* NavigationBarDelegate */ = {
               | 
            
| 1058 | 1062 | 
                isa = PBXGroup;  | 
            
| 1059 | 1063 | 
                children = (  | 
            
                @@ -1275,9 +1279,9 @@  | 
            ||
| 1275 | 1279 | 
                isa = PBXGroup;  | 
            
| 1276 | 1280 | 
                children = (  | 
            
| 1277 | 1281 | 
                0513106821CA34D6004EF1BE /* GroupDetailCoordinator.swift */,  | 
            
| 1278 | 
                - A69FFAB61E7004700006FEE0 /* MemberCell.swift */,  | 
            |
| 1279 | 
                - A69FFAB11E7004700006FEE0 /* GroupDetailController.swift */,  | 
            |
| 1282 | 
                + A69FFAB11E7004700006FEE0 /* GroupDetailViewController.swift */,  | 
            |
| 1280 | 1283 | 
                A69FFAB41E7004700006FEE0 /* GroupMemberController.swift */,  | 
            
| 1284 | 
                + A69FFAB61E7004700006FEE0 /* MemberCell.swift */,  | 
            |
| 1281 | 1285 | 
                A69FFAAE1E7004700006FEE0 /* ChangeGroupNameController.swift */,  | 
            
| 1282 | 1286 | 
                A69FFAB71E7004700006FEE0 /* ShowGroupQRController.swift */,  | 
            
| 1283 | 1287 | 
                A69FFB8A1E7018CC0006FEE0 /* GroupDetail.storyboard */,  | 
            
                @@ -1290,6 +1294,7 @@  | 
            ||
| 1290 | 1294 | 
                children = (  | 
            
| 1291 | 1295 | 
                05D3A3CC22000C3900A29A20 /* GroupCoordinator.swift */,  | 
            
| 1292 | 1296 | 
                A69FFAAB1E7004700006FEE0 /* GroupViewController.swift */,  | 
            
| 1297 | 
                + 055EFAD6221A4DB400450AD5 /* GroupQRView.swift */,  | 
            |
| 1293 | 1298 | 
                0569F613220042AF000A75CA /* Group.storyboard */,  | 
            
| 1294 | 1299 | 
                05D790AE1FC50E7C00469AD1 /* GroupDetail */,  | 
            
| 1295 | 1300 | 
                );  | 
            
                @@ -1704,6 +1709,7 @@  | 
            ||
| 1704 | 1709 | 
                053E126F21F5774700A64893 /* FadeToastAnimator.swift in Sources */,  | 
            
| 1705 | 1710 | 
                05130FFE21CA1B39004EF1BE /* WaterfallFlowLayout.swift in Sources */,  | 
            
| 1706 | 1711 | 
                05130FFF21CA1B39004EF1BE /* WaterfallFlowConfiguration.swift in Sources */,  | 
            
| 1712 | 
                + 055BB53E220AEA3B009548AA /* NiblessViewController.swift in Sources */,  | 
            |
| 1707 | 1713 | 
                0513100021CA1B39004EF1BE /* CLLocationExt.swift in Sources */,  | 
            
| 1708 | 1714 | 
                059B58AA21F83B2E00FA64C2 /* CenterConfirmItem.swift in Sources */,  | 
            
| 1709 | 1715 | 
                05C5285E21FEB03F0090ECB5 /* ViewControllerTransitioningProxy.swift in Sources */,  | 
            
                @@ -1734,11 +1740,10 @@  | 
            ||
| 1734 | 1740 | 
                0513100B21CA1B39004EF1BE /* UIColorExt.swift in Sources */,  | 
            
| 1735 | 1741 | 
                05C8D21221ED7B620001E847 /* UINavigationBar+FixSpace.swift in Sources */,  | 
            
| 1736 | 1742 | 
                05C8D21021ED7B280001E847 /* UIApplication+Swizzle.swift in Sources */,  | 
            
| 1737 | 
                - 0513100E21CA1B39004EF1BE /* UIButtonExt.swift in Sources */,  | 
            |
| 1738 | 1743 | 
                0569F61A22014B30000A75CA /* NavigationBarProxy.swift in Sources */,  | 
            
| 1739 | 1744 | 
                0513100F21CA1B39004EF1BE /* UIViewExt.swift in Sources */,  | 
            
| 1740 | 
                - 053E125F21F16BA400A64893 /* ToastTextView.swift in Sources */,  | 
            |
| 1741 | 1745 | 
                0513109B21CA3915004EF1BE /* QRCodeConfiguration.swift in Sources */,  | 
            
| 1746 | 
                + 055BB541220AEA62009548AA /* NiblessView.swift in Sources */,  | 
            |
| 1742 | 1747 | 
                0513101021CA1B39004EF1BE /* UIViewControllerExt.swift in Sources */,  | 
            
| 1743 | 1748 | 
                0513101221CA1B39004EF1BE /* UITextFieldExt.swift in Sources */,  | 
            
| 1744 | 1749 | 
                05C0CEF921F8567C00993DE2 /* AlertView.swift in Sources */,  | 
            
                @@ -1751,7 +1756,6 @@  | 
            ||
| 1751 | 1756 | 
                05D3A3D02200288400A29A20 /* Storyboarded.swift in Sources */,  | 
            
| 1752 | 1757 | 
                05C0CEFB21F85A7700993DE2 /* ActionSheetController.swift in Sources */,  | 
            
| 1753 | 1758 | 
                05C8D21421ED8B9B0001E847 /* NavigationBackViewController.swift in Sources */,  | 
            
| 1754 | 
                - 053E126121F16BB100A64893 /* ToastImageView.swift in Sources */,  | 
            |
| 1755 | 1759 | 
                0584FD7C21FABC1400FA1E3E /* PresentExtension.swift in Sources */,  | 
            
| 1756 | 1760 | 
                05C8D21B21ED9A020001E847 /* UIViewController+Navigation.swift in Sources */,  | 
            
| 1757 | 1761 | 
                0513109521CA3915004EF1BE /* QRCodeScanDelegate.swift in Sources */,  | 
            
                @@ -1780,7 +1784,6 @@  | 
            ||
| 1780 | 1784 | 
                05C5285821FE995F0090ECB5 /* GestureRecognizerDelegate.swift in Sources */,  | 
            
| 1781 | 1785 | 
                05130F6321C94C7A004EF1BE /* SideViewController.swift in Sources */,  | 
            
| 1782 | 1786 | 
                05130F6421C94C7A004EF1BE /* PageViewController.swift in Sources */,  | 
            
| 1783 | 
                - 053E126321F16EF300A64893 /* ToastContentView.swift in Sources */,  | 
            |
| 1784 | 1787 | 
                );  | 
            
| 1785 | 1788 | 
                runOnlyForDeploymentPostprocessing = 0;  | 
            
| 1786 | 1789 | 
                };  | 
            
                @@ -1866,10 +1869,11 @@  | 
            ||
| 1866 | 1869 | 
                051310B621CB675A004EF1BE /* UIImageView+Kingfisher.swift in Sources */,  | 
            
| 1867 | 1870 | 
                05130FDD21CA1B04004EF1BE /* GroupViewController.swift in Sources */,  | 
            
| 1868 | 1871 | 
                05130FDF21CA1B04004EF1BE /* MemberCell.swift in Sources */,  | 
            
| 1869 | 
                - 05130FE021CA1B04004EF1BE /* GroupDetailController.swift in Sources */,  | 
            |
| 1872 | 
                + 05130FE021CA1B04004EF1BE /* GroupDetailViewController.swift in Sources */,  | 
            |
| 1870 | 1873 | 
                05130FE121CA1B04004EF1BE /* GroupMemberController.swift in Sources */,  | 
            
| 1871 | 1874 | 
                05130FE221CA1B04004EF1BE /* ChangeGroupNameController.swift in Sources */,  | 
            
| 1872 | 1875 | 
                05130FE321CA1B04004EF1BE /* ShowGroupQRController.swift in Sources */,  | 
            
| 1876 | 
                + 055EFAD7221A4DB400450AD5 /* GroupQRView.swift in Sources */,  | 
            |
| 1873 | 1877 | 
                05130FE421CA1B04004EF1BE /* MessageCommentAndThumbupCell.swift in Sources */,  | 
            
| 1874 | 1878 | 
                05D3A3CD22000C3A00A29A20 /* GroupCoordinator.swift in Sources */,  | 
            
| 1875 | 1879 | 
                05130FE521CA1B04004EF1BE /* MessageSystemCell.swift in Sources */,  | 
            
                @@ -2,4 +2,16 @@  | 
            ||
| 2 | 2 | 
                <Bucket  | 
            
| 3 | 3 | 
                type = "1"  | 
            
| 4 | 4 | 
                version = "2.0">  | 
            
| 5 | 
                + <Breakpoints>  | 
            |
| 6 | 
                + <BreakpointProxy  | 
            |
| 7 | 
                + BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">  | 
            |
| 8 | 
                + <BreakpointContent  | 
            |
| 9 | 
                + shouldBeEnabled = "Yes"  | 
            |
| 10 | 
                + ignoreCount = "0"  | 
            |
| 11 | 
                + continueAfterRunningActions = "No"  | 
            |
| 12 | 
                + scope = "0"  | 
            |
| 13 | 
                + stopOnStyle = "0">  | 
            |
| 14 | 
                + </BreakpointContent>  | 
            |
| 15 | 
                + </BreakpointProxy>  | 
            |
| 16 | 
                + </Breakpoints>  | 
            |
| 5 | 17 | 
                </Bucket>  | 
            
                @@ -22,7 +22,7 @@ struct GroupPhotoRepository {
               | 
            ||
| 22 | 22 | 
                return groupPhotoRemoteAPI.loadContent()  | 
            
| 23 | 23 | 
                }  | 
            
| 24 | 24 | 
                 | 
            
| 25 | 
                -    func upload(data: Data) -> Single<PhotoItem> {
               | 
            |
| 25 | 
                +    func upload(data: Data) -> Single<[PhotoItem]> {
               | 
            |
| 26 | 26 | 
                return groupPhotoRemoteAPI.uploadPhoto(data: data)  | 
            
| 27 | 27 | 
                }  | 
            
| 28 | 28 | 
                }  | 
            
                @@ -19,33 +19,28 @@ struct GroupPhotoRemoteAPI {
               | 
            ||
| 19 | 19 | 
                     private func parse(_ json: JSON) -> [PhotoItem]? {
               | 
            
| 20 | 20 | 
                guard let data = json["data"] as? [String: AnyObject],  | 
            
| 21 | 21 | 
                             let photos = data["photos"] as? [[String: AnyObject]] else { return nil }
               | 
            
| 22 | 
                -        let dataArr = photos.compactMap { $0 }
               | 
            |
| 22 | 
                +        let dataArr = photos.compactMap { $0["photos"] as? [[String: AnyObject]] }.flatMap { $0 }
               | 
            |
| 23 | 23 | 
                         return dataArr.map { PhotoItem(json: $0) }
               | 
            
| 24 | 24 | 
                }  | 
            
| 25 | 
                -  | 
            |
| 26 | 
                -    private func parseUpload(_ json: JSON) -> PhotoItem? {
               | 
            |
| 27 | 
                - guard let data = json["data"] as? [String: AnyObject],  | 
            |
| 28 | 
                -            let photos = data["photos"] as? [[String: AnyObject]] else { return nil }
               | 
            |
| 29 | 
                -        let dataArr = photos.compactMap { $0 }
               | 
            |
| 30 | 
                - return PhotoItem(json: dataArr[0])  | 
            |
| 31 | 
                - }  | 
            |
| 32 | 25 | 
                 | 
            
| 33 | 26 | 
                     func loadContent() -> Single<[PhotoItem]> {
               | 
            
| 34 | 27 | 
                let resource = ContentResource<[PhotoItem]>(path: .groupPhotoList,  | 
            
| 35 | 28 | 
                parameter: ["user_id": ShareUserId,  | 
            
| 36 | 
                - "group_id": groupId],  | 
            |
| 29 | 
                + "group_id": groupId,  | 
            |
| 30 | 
                + "current_id": -1],  | 
            |
| 37 | 31 | 
                parseJSON: parse)  | 
            
| 38 | 32 | 
                return resource.loadContent()  | 
            
| 39 | 33 | 
                }  | 
            
| 40 | 34 | 
                 | 
            
| 41 | 
                -    func uploadPhoto(data: Data) -> Single<PhotoItem> {
               | 
            |
| 42 | 
                - let name = groupId + "" + "\(Date.timeIntervalSinceReferenceDate)"  | 
            |
| 43 | 
                - let file = FileModel(name: name, fileData: data)  | 
            |
| 44 | 
                - let uploadResource = UploadResource<PhotoItem>(path: .photoUpload,  | 
            |
| 35 | 
                +    func uploadPhoto(data: Data) -> Single<[PhotoItem]> {
               | 
            |
| 36 | 
                +// let name = groupId + "" + "\(Date.timeIntervalSinceReferenceDate)"  | 
            |
| 37 | 
                + let file = FileModel(name: "photo", fileData: data)  | 
            |
| 38 | 
                + let uploadResource = UploadResource<[PhotoItem]>(path: .photoUpload,  | 
            |
| 45 | 39 | 
                parameter: ["user_id": ShareUserId,  | 
            
| 46 | 40 | 
                "group_id": groupId,  | 
            
| 41 | 
                + "current_id": -1,  | 
            |
| 47 | 42 | 
                "photo": file],  | 
            
| 48 | 
                - parseJSON: parseUpload)  | 
            |
| 43 | 
                + parseJSON: parse)  | 
            |
| 49 | 44 | 
                 | 
            
| 50 | 45 | 
                return uploadResource.upload()  | 
            
| 51 | 46 | 
                }  | 
            
                @@ -118,6 +118,7 @@ class NetworkApi {
               | 
            ||
| 118 | 118 | 
                }  | 
            
| 119 | 119 | 
                 | 
            
| 120 | 120 | 
                     public func upload<A: Resource>(resource: A) -> Single<A.Model> {
               | 
            
| 121 | 
                + print(resource.parameter)  | 
            |
| 121 | 122 | 
                         return Single<A.Model>.create(subscribe: { (observer) in
               | 
            
| 122 | 123 | 
                             let request = self.session.upload(multipartFormData: { (multiPartData) in
               | 
            
| 123 | 124 | 
                                 for (key, value) in resource.parameter {
               | 
            
                @@ -6,7 +6,6 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2017年 FFIB. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import Foundation  | 
            |
| 10 | 9 | 
                import UIKit  | 
            
| 11 | 10 | 
                import RxSwift  | 
            
| 12 | 11 | 
                import RxCocoa  | 
            
                @@ -15,7 +14,6 @@ import RxDataSources  | 
            ||
| 15 | 14 | 
                 public protocol GroupViewModelDelegate: class {
               | 
            
| 16 | 15 | 
                func didSelect(_ item: PhotoItem)  | 
            
| 17 | 16 | 
                func navigateToGroupDetail()  | 
            
| 18 | 
                - func presentGroupQR()  | 
            |
| 19 | 17 | 
                }  | 
            
| 20 | 18 | 
                 | 
            
| 21 | 19 | 
                 public class GroupViewModel {
               | 
            
                @@ -27,8 +25,6 @@ public class GroupViewModel {
               | 
            ||
| 27 | 25 | 
                private var _isLoading = PublishSubject<Void>()  | 
            
| 28 | 26 | 
                private let items = BehaviorRelay<[PhotoItem]>(value: [])  | 
            
| 29 | 27 | 
                 | 
            
| 30 | 
                - public var photographBtnTapped = PublishSubject<Void>()  | 
            |
| 31 | 
                -  | 
            |
| 32 | 28 | 
                 | 
            
| 33 | 29 | 
                     public var isLoading: Observable<Void> {
               | 
            
| 34 | 30 | 
                return _isLoading.asObservable()  | 
            
                @@ -44,40 +40,36 @@ public class GroupViewModel {
               | 
            ||
| 44 | 40 | 
                 | 
            
| 45 | 41 | 
                     public init(groupItem: GroupItem) {
               | 
            
| 46 | 42 | 
                self.respository = GroupPhotoRepository(groupId: groupItem.group_id)  | 
            
| 47 | 
                -  | 
            |
| 48 | 
                -  | 
            |
| 49 | 
                -        photographBtnTapped.subscribe({
               | 
            |
| 50 | 
                - [weak self] (_) in  | 
            |
| 51 | 
                -            guard let `self` = self else { return }
               | 
            |
| 52 | 
                -// self.delegate?.scanQR()  | 
            |
| 53 | 
                - }).disposed(by: disposeBag)  | 
            |
| 54 | 43 | 
                }  | 
            
| 55 | 44 | 
                 | 
            
| 56 | 45 | 
                     public func reload() {
               | 
            
| 57 | 46 | 
                respository.load()  | 
            
| 58 | 47 | 
                             .subscribe(onSuccess: {[weak self] (result) in
               | 
            
| 59 | 
                -                guard let `self` = self else { return }                
               | 
            |
| 48 | 
                +                guard let `self` = self else { return }
               | 
            |
| 60 | 49 | 
                self._isLoading.onNext(())  | 
            
| 61 | 50 | 
                self.items.accept(result)  | 
            
| 62 | 
                -                }, onError: {[weak self] (_) in
               | 
            |
| 51 | 
                +                }, onError: {[weak self] (error) in
               | 
            |
| 63 | 52 | 
                                     guard let `self` = self else { return }
               | 
            
| 64 | 53 | 
                self._isLoading.onNext(())  | 
            
| 65 | 54 | 
                }).disposed(by: disposeBag)  | 
            
| 66 | 55 | 
                }  | 
            
| 67 | 56 | 
                 | 
            
| 68 | 
                -    public func submit(image: UIImage) {
               | 
            |
| 69 | 
                - let edge = image.size.width > image.size.height ? image.size.height : image.size.width  | 
            |
| 70 | 
                -// let newImage = image.scaledImage(1280 / edge),  | 
            |
| 71 | 
                -        guard let data = image.jpegData(compressionQuality: 0.4) else { return }
               | 
            |
| 72 | 
                -  | 
            |
| 73 | 
                - respository.upload(data: data)  | 
            |
| 57 | 
                +    public func submit(data: Data) {
               | 
            |
| 58 | 
                +        respository.upload(data: data).subscribe(onSuccess: { [weak self] result in
               | 
            |
| 59 | 
                +            guard let `self` = self else { return }
               | 
            |
| 60 | 
                + self.items.accept(result)  | 
            |
| 61 | 
                + self._isLoading.onNext(())  | 
            |
| 62 | 
                +        }) {[weak self] (error) in
               | 
            |
| 63 | 
                +            guard let  `self` = self else { return }
               | 
            |
| 64 | 
                + self._isLoading.onNext(())  | 
            |
| 65 | 
                + }.disposed(by: disposeBag)  | 
            |
| 74 | 66 | 
                }  | 
            
| 75 | 67 | 
                 | 
            
| 76 | 68 | 
                     public func layoutSizeForIndexPath(_ indexPath: IndexPath) -> CGSize {
               | 
            
| 77 | 69 | 
                let item = items.value[indexPath.row]  | 
            
| 78 | 70 | 
                let w = item.photo_thumbnail_w  | 
            
| 79 | 71 | 
                let h = item.photo_thumbnail_h  | 
            
| 80 | 
                -  | 
            |
| 72 | 
                +  | 
            |
| 81 | 73 | 
                // header 42, footer: 32  | 
            
| 82 | 74 | 
                return CGSize(width: w, height: h + 74)  | 
            
| 83 | 75 | 
                }  | 
            
                @@ -92,9 +84,4 @@ public extension GroupViewModel {
               | 
            ||
| 92 | 84 | 
                     @objc func navigateToGroupDetail() {
               | 
            
| 93 | 85 | 
                delegate?.navigateToGroupDetail()  | 
            
| 94 | 86 | 
                }  | 
            
| 95 | 
                -  | 
            |
| 96 | 
                -  | 
            |
| 97 | 
                -    @objc func presentGroupQR() {
               | 
            |
| 98 | 
                - delegate?.presentGroupQR()  | 
            |
| 99 | 
                - }  | 
            |
| 100 | 87 | 
                }  | 
            
                @@ -16,7 +16,7 @@ public extension UIBarButtonItem {
               | 
            ||
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                     convenience init(image: UIImage?, target: Any, action: Selector) {
               | 
            
| 18 | 18 | 
                let button = UIButton(type: .custom)  | 
            
| 19 | 
                - button.frame = CGRect(x: 0, y: 0, width: 40, height: 40)  | 
            |
| 19 | 
                + button.frame = CGRect(x: 0, y: 0, width: 36, height: 36)  | 
            |
| 20 | 20 | 
                button.setImage(image, for: .normal)  | 
            
| 21 | 21 | 
                button.addTarget(target, action: action, for: .touchDown)  | 
            
| 22 | 22 | 
                self.init(customView: button)  | 
            
                @@ -24,7 +24,7 @@ public extension UIBarButtonItem {
               | 
            ||
| 24 | 24 | 
                 | 
            
| 25 | 25 | 
                     convenience init(title: String, target: Any, action: Selector) {
               | 
            
| 26 | 26 | 
                let button = UIButton(type: .custom)  | 
            
| 27 | 
                - button.frame = CGRect(x: 0, y: 0, width: 44, height: 44)  | 
            |
| 27 | 
                + button.frame = CGRect(x: 0, y: 0, width: 36, height: 36)  | 
            |
| 28 | 28 | 
                button.setTitle(title, for: .normal)  | 
            
| 29 | 29 | 
                button.addTarget(target, action: action, for: .touchDown)  | 
            
| 30 | 30 | 
                button.sizeToFit()  | 
            
                @@ -36,7 +36,7 @@ public extension UIBarButtonItem {
               | 
            ||
| 36 | 36 | 
                var lastX: CGFloat = 0  | 
            
| 37 | 37 | 
                         for (title, action) in zip(titles, actions) {
               | 
            
| 38 | 38 | 
                let button = UIButton(type: .custom)  | 
            
| 39 | 
                - button.frame = CGRect(x: lastX, y: 2, width: 40, height: 40)  | 
            |
| 39 | 
                + button.frame = CGRect(x: lastX, y: 2, width: 36, height: 36)  | 
            |
| 40 | 40 | 
                button.setTitle(title, for: .normal)  | 
            
| 41 | 41 | 
                button.addTarget(target, action: action, for: .touchDown)  | 
            
| 42 | 42 | 
                button.sizeToFit()  | 
            
                @@ -48,30 +48,22 @@ public extension UIBarButtonItem {
               | 
            ||
| 48 | 48 | 
                self.init(customView: barView)  | 
            
| 49 | 49 | 
                }  | 
            
| 50 | 50 | 
                 | 
            
| 51 | 
                -    convenience init(images: [UIImage?], btnSpace: CGFloat, target: Any, actions: [Selector]) {
               | 
            |
| 51 | 
                +    convenience init(images: [UIImage?], btnSpace: CGFloat = 0, targets: [Any], actions: [Selector]) {
               | 
            |
| 52 | 52 | 
                let barView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 36))  | 
            
| 53 | 
                - barView.backgroundColor = UIColor.cyan  | 
            |
| 54 | 53 | 
                 | 
            
| 55 | 
                - var last: UIButton?  | 
            |
| 56 | 
                -        for (image, action) in zip(images, actions) {
               | 
            |
| 54 | 
                + var lastX: CGFloat = 0  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +        for (target, (image, action)) in zip(targets, zip(images, actions)) {
               | 
            |
| 57 | 57 | 
                let button = UIButton(type: .custom)  | 
            
| 58 | 
                - button.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 58 | 
                + button.frame = CGRect(x: lastX, y: 2, width: 36, height: 36)  | 
            |
| 59 | 59 | 
                button.setImage(image, for: .normal)  | 
            
| 60 | 60 | 
                button.addTarget(target, action: action, for: .touchDown)  | 
            
| 61 | 61 | 
                barView.addSubview(button)  | 
            
| 62 | 62 | 
                 | 
            
| 63 | 
                - NSLayoutConstraint.activate([  | 
            |
| 64 | 
                - button.widthAnchor.constraint(equalToConstant: 36),  | 
            |
| 65 | 
                - button.heightAnchor.constraint(equalToConstant: 36),  | 
            |
| 66 | 
                - button.centerYAnchor.constraint(equalTo: barView.centerYAnchor),  | 
            |
| 67 | 
                - button.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? barView.leadingAnchor)  | 
            |
| 68 | 
                - ])  | 
            |
| 69 | 
                - last = button  | 
            |
| 63 | 
                + lastX += button.width + btnSpace  | 
            |
| 70 | 64 | 
                }  | 
            
| 71 | 65 | 
                 | 
            
| 72 | 
                -        if let l = last {
               | 
            |
| 73 | 
                - NSLayoutConstraint.activate([l.trailingAnchor.constraint(equalTo: barView.trailingAnchor)])  | 
            |
| 74 | 
                - }  | 
            |
| 66 | 
                + barView.width = lastX - btnSpace  | 
            |
| 75 | 67 | 
                 | 
            
| 76 | 68 | 
                self.init(customView: barView)  | 
            
| 77 | 69 | 
                }  | 
            
                @@ -11,24 +11,17 @@ import UIKit  | 
            ||
| 11 | 11 | 
                 public extension UIImage {
               | 
            
| 12 | 12 | 
                 | 
            
| 13 | 13 | 
                     func scaledImage(_ scale: CGFloat) -> UIImage? {
               | 
            
| 14 | 
                - let rect = CGRect(x: 0, y: 0, width: self.size.width * scale, height: self.size.height * scale).integral  | 
            |
| 15 | 
                - UIGraphicsBeginImageContextWithOptions(rect.size, true, UIScreen.main.scale)  | 
            |
| 16 | 
                - self.draw(in: rect)  | 
            |
| 17 | 
                - let image = UIGraphicsGetImageFromCurrentImageContext()  | 
            |
| 18 | 
                - UIGraphicsEndImageContext()  | 
            |
| 19 | 
                - return image  | 
            |
| 14 | 
                + let outputSize = size * scale  | 
            |
| 15 | 
                + let renderer = UIGraphicsImageRenderer(size: outputSize)  | 
            |
| 16 | 
                +        return renderer.image(actions: {_ in })
               | 
            |
| 20 | 17 | 
                }  | 
            
| 21 | 18 | 
                 | 
            
| 22 | 
                -    static func imageWithColor(_ color: UIColor) -> UIImage {
               | 
            |
| 23 | 
                - let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)  | 
            |
| 24 | 
                - UIGraphicsBeginImageContext(rect.size)  | 
            |
| 25 | 
                - let context = UIGraphicsGetCurrentContext()  | 
            |
| 26 | 
                - context?.setFillColor(color.cgColor)  | 
            |
| 27 | 
                - context?.fill(rect)  | 
            |
| 28 | 
                - let image = UIGraphicsGetImageFromCurrentImageContext()  | 
            |
| 29 | 
                - UIGraphicsEndImageContext()  | 
            |
| 30 | 
                - return image!  | 
            |
| 19 | 
                +    func scaledImage(length: CGFloat, with quality: CGFloat) -> Data? {
               | 
            |
| 20 | 
                + let edge = size.width > size.height ? size.height : size.width  | 
            |
| 21 | 
                + let outputSize = size * (length / edge)  | 
            |
| 31 | 22 | 
                 | 
            
| 23 | 
                + let renderer = UIGraphicsImageRenderer(size: outputSize)  | 
            |
| 24 | 
                +        return renderer.image(actions: {_ in }).jpegData(compressionQuality: quality)
               | 
            |
| 32 | 25 | 
                }  | 
            
| 33 | 26 | 
                }  | 
            
| 34 | 27 | 
                 | 
            
                @@ -8,8 +8,8 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 
                -struct ActionSheetAnimator: PresentAnimatable {
               | 
            |
| 12 | 
                -    func contentViewAppearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 11 | 
                +public struct ActionSheetAnimator: PresentAnimatable {
               | 
            |
| 12 | 
                +    public func contentViewAppearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 13 | 13 | 
                let animation = CATransition()  | 
            
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                animation.duration = duration  | 
            
                @@ -19,7 +19,7 @@ struct ActionSheetAnimator: PresentAnimatable {
               | 
            ||
| 19 | 19 | 
                view.layer.add(animation, forKey: nil)  | 
            
| 20 | 20 | 
                }  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 
                -    func contentViewDisappearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 22 | 
                +    public func contentViewDisappearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 23 | 23 | 
                let fromValue = view.layer.position.y  | 
            
| 24 | 24 | 
                let toValue = fromValue + view.bounds.height  | 
            
| 25 | 25 | 
                 | 
            
                @@ -8,8 +8,11 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 
                -struct AlertAnimator: PresentAnimatable {
               | 
            |
| 12 | 
                -    func contentViewAppearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 11 | 
                +public struct AlertAnimator: PresentAnimatable {
               | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +    public init() {}
               | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +    public func contentViewAppearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 13 | 16 | 
                let animation = CABasicAnimation(keyPath: "transform.scale")  | 
            
| 14 | 17 | 
                 | 
            
| 15 | 18 | 
                animation.toValue = 1  | 
            
                @@ -20,7 +23,7 @@ struct AlertAnimator: PresentAnimatable {
               | 
            ||
| 20 | 23 | 
                view.layer.add(animation, forKey: nil)  | 
            
| 21 | 24 | 
                }  | 
            
| 22 | 25 | 
                 | 
            
| 23 | 
                -    func contentViewDisappearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 26 | 
                +    public func contentViewDisappearAnimation(duration: TimeInterval, in view: UIView) {
               | 
            |
| 24 | 27 | 
                let animation = CAKeyframeAnimation(keyPath: "transform.scale")  | 
            
| 25 | 28 | 
                 | 
            
| 26 | 29 | 
                animation.values = [1, 1.1, 0]  | 
            
                @@ -12,6 +12,10 @@ import UIKit  | 
            ||
| 12 | 12 | 
                 open class AlertViewController: UIViewController, PresentViewController {
               | 
            
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                     open var animationView: UIView? {
               | 
            
| 15 | 
                +        if case let .custom(alertView, _) = style {
               | 
            |
| 16 | 
                + return alertView  | 
            |
| 17 | 
                + }  | 
            |
| 18 | 
                +  | 
            |
| 15 | 19 | 
                return nil  | 
            
| 16 | 20 | 
                }  | 
            
| 17 | 21 | 
                 | 
            
                @@ -29,7 +33,7 @@ open class AlertViewController: UIViewController, PresentViewController {
               | 
            ||
| 29 | 33 | 
                 | 
            
| 30 | 34 | 
                public var animator: PresentAnimatable = AlertAnimator()  | 
            
| 31 | 35 | 
                 | 
            
| 32 | 
                -    init(style: Style = .alert) {
               | 
            |
| 36 | 
                +    public init(style: Style = .alert) {
               | 
            |
| 33 | 37 | 
                _style = style  | 
            
| 34 | 38 | 
                super.init(nibName: nil, bundle: nil)  | 
            
| 35 | 39 | 
                commonInit()  | 
            
                @@ -32,11 +32,6 @@ public class AlertController: AlertViewController {
               | 
            ||
| 32 | 32 | 
                return alertView.confirmItem  | 
            
| 33 | 33 | 
                }  | 
            
| 34 | 34 | 
                 | 
            
| 35 | 
                -    public override func viewDidLoad() {
               | 
            |
| 36 | 
                - super.viewDidLoad()  | 
            |
| 37 | 
                - view.addSubview(alertView)  | 
            |
| 38 | 
                - }  | 
            |
| 39 | 
                -  | 
            |
| 40 | 35 | 
                /// title and message is only avilable in type is alert  | 
            
| 41 | 36 | 
                     public init(title: String = "", message: String = "", contentView: UIView? = nil) {
               | 
            
| 42 | 37 | 
                alertView = .default  | 
            
                @@ -20,7 +20,7 @@ public final class AlertView: UIView {
               | 
            ||
| 20 | 20 | 
                private var cancelAction: AlertAction?  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                     public var cancelItem: AlertItem = {
               | 
            
| 23 | 
                - let item = AlertItem(type: .custom)  | 
            |
| 23 | 
                + let item = AlertItem(type: .custom)  | 
            |
| 24 | 24 | 
                item.backgroundColor = UIColor(r: 214, g: 214, b: 214)  | 
            
| 25 | 25 | 
                item.setTitleColor(UIColor(r: 51, g: 51, b: 51), for: .normal)  | 
            
| 26 | 26 | 
                 | 
            
                @@ -19,7 +19,7 @@ public extension NavigationBackDelegate where Self: UIViewController {
               | 
            ||
| 19 | 19 | 
                btn.contentHorizontalAlignment = .left  | 
            
| 20 | 20 | 
                btn.frame = CGRect(x: 0, y: 0, width: 40 , height: 40)  | 
            
| 21 | 21 | 
                btn.setImage(UIImage(named: "navigation-back"), for: .normal)  | 
            
| 22 | 
                - btn.addTarget(self, action: #selector(backToViewController), for: .touchUpInside)  | 
            |
| 22 | 
                + btn.addTarget(self, action: #selector(backToViewController), for: .touchDown)  | 
            |
| 23 | 23 | 
                 | 
            
| 24 | 24 | 
                let backItem = UIBarButtonItem(customView: btn)  | 
            
| 25 | 25 | 
                let spaceItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)  | 
            
                @@ -6,4 +6,16 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2019 yb. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import Foundation  | 
            |
| 9 | 
                +import UIKit  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +open class NiblessView: UIView {
               | 
            |
| 12 | 
                +    public override init(frame: CGRect) {
               | 
            |
| 13 | 
                + super.init(frame: frame)  | 
            |
| 14 | 
                + }  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                + @available(*, unavailable, message: "Loading this view from a nib is unsupported")  | 
            |
| 17 | 
                +    public required init?(coder aDecoder: NSCoder) {
               | 
            |
| 18 | 
                +        fatalError("Loading this view from a nib is unsupported")
               | 
            |
| 19 | 
                + }  | 
            |
| 20 | 
                +}  | 
            |
| 21 | 
                +  | 
            
                @@ -8,23 +8,19 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 
                -class NiblessViewController: UIViewController {
               | 
            |
| 12 | 
                -  | 
            |
| 13 | 
                -    override func viewDidLoad() {
               | 
            |
| 14 | 
                - super.viewDidLoad()  | 
            |
| 15 | 
                -  | 
            |
| 16 | 
                - // Do any additional setup after loading the view.  | 
            |
| 11 | 
                +open class NiblessViewController: UIViewController {
               | 
            |
| 12 | 
                + /// - Methods  | 
            |
| 13 | 
                +    public init() {
               | 
            |
| 14 | 
                + super.init(nibName: nil, bundle: nil)  | 
            |
| 17 | 15 | 
                }  | 
            
| 18 | 16 | 
                 | 
            
| 19 | 
                -  | 
            |
| 20 | 
                - /*  | 
            |
| 21 | 
                - // MARK: - Navigation  | 
            |
| 22 | 
                -  | 
            |
| 23 | 
                - // In a storyboard-based application, you will often want to do a little preparation before navigation  | 
            |
| 24 | 
                -    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
               | 
            |
| 25 | 
                - // Get the new view controller using segue.destination.  | 
            |
| 26 | 
                - // Pass the selected object to the new view controller.  | 
            |
| 17 | 
                + @available(*, unavailable, message: "Loading this view controller from a nib is unsupported")  | 
            |
| 18 | 
                +    public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
               | 
            |
| 19 | 
                + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)  | 
            |
| 20 | 
                + }  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                + @available(*, unavailable, message: "Loading this view controller from a nib is unsupported")  | 
            |
| 23 | 
                +    public required init(coder aDecoder: NSCoder) {
               | 
            |
| 24 | 
                +        fatalError("Loading this view controller from a nib is unsupported")
               | 
            |
| 27 | 25 | 
                }  | 
            
| 28 | 
                - */  | 
            |
| 29 | 
                -  | 
            |
| 30 | 26 | 
                }  | 
            
                @@ -28,6 +28,7 @@ final class PresentAppearAnimatedTransitioning: NSObject, UIViewControllerAnimat  | 
            ||
| 28 | 28 | 
                             let animationView = delegate?.animationView else { return }
               | 
            
| 29 | 29 | 
                 | 
            
| 30 | 30 | 
                transitionContext.containerView.addSubview(toView)  | 
            
| 31 | 
                + toView.addSubview(animationView)  | 
            |
| 31 | 32 | 
                 | 
            
| 32 | 33 | 
                let duration = transitionDuration(using: transitionContext)  | 
            
| 33 | 34 | 
                 | 
            
                @@ -28,7 +28,7 @@ final class PresentDisappearAnimatedTransitioning: NSObject, UIViewControllerAni  | 
            ||
| 28 | 28 | 
                let toVC = transitionContext.viewController(forKey: .to),  | 
            
| 29 | 29 | 
                let toView = toVC.view,  | 
            
| 30 | 30 | 
                             let animationView = delegate?.animationView else { return }
               | 
            
| 31 | 
                -  | 
            |
| 31 | 
                +  | 
            |
| 32 | 32 | 
                let duration = transitionDuration(using: transitionContext)  | 
            
| 33 | 33 | 
                 | 
            
| 34 | 34 | 
                animator.fromViewPresentingAnimation(duration: duration, in: fromView)  | 
            
                @@ -37,7 +37,7 @@ extension NSObject {
               | 
            ||
| 37 | 37 | 
                }  | 
            
| 38 | 38 | 
                }  | 
            
| 39 | 39 | 
                 | 
            
| 40 | 
                -extension UIImage {
               | 
            |
| 40 | 
                +public extension UIImage {
               | 
            |
| 41 | 41 | 
                //init with qr code string  | 
            
| 42 | 42 | 
                 | 
            
| 43 | 43 | 
                /// 初始化一个qr  | 
            
                @@ -45,7 +45,7 @@ extension UIImage {
               | 
            ||
| 45 | 45 | 
                /// - Parameters:  | 
            
| 46 | 46 | 
                /// - qr: qr携带的信息  | 
            
| 47 | 47 | 
                /// - size: qr的大小  | 
            
| 48 | 
                -    convenience init?(qr: String, size: CGSize?) {
               | 
            |
| 48 | 
                +    convenience init?(qr: String, size: CGSize? = nil) {
               | 
            |
| 49 | 49 | 
                 | 
            
| 50 | 50 | 
                         guard let qrImageFilter = CIFilter(name: "CIQRCodeGenerator") else {
               | 
            
| 51 | 51 | 
                self.init(named: "")  | 
            
                @@ -13,9 +13,9 @@ private let globalInstance = Toast()  | 
            ||
| 13 | 13 | 
                 public class Toast {
               | 
            
| 14 | 14 | 
                     public enum ToastType {
               | 
            
| 15 | 15 | 
                case text(String)  | 
            
| 16 | 
                - case image(UIImage)  | 
            |
| 17 | 
                - case imageWithText(UIImage, String)  | 
            |
| 18 | 
                - case activityIndicator  | 
            |
| 16 | 
                + case image(UIImage?)  | 
            |
| 17 | 
                + case imageWithText(UIImage?, String)  | 
            |
| 18 | 
                + case activityIndicator(String?)  | 
            |
| 19 | 19 | 
                }  | 
            
| 20 | 20 | 
                 | 
            
| 21 | 21 | 
                     public enum PresentationStyle {
               | 
            
                @@ -64,6 +64,24 @@ public extension Toast {
               | 
            ||
| 64 | 64 | 
                show(config: config, in: view)  | 
            
| 65 | 65 | 
                }  | 
            
| 66 | 66 | 
                 | 
            
| 67 | 
                +    func show(image: UIImage?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 68 | 
                + var config = Config()  | 
            |
| 69 | 
                + config.toastType = .image(image)  | 
            |
| 70 | 
                + show(config: config, in: view)  | 
            |
| 71 | 
                + }  | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                +    func show(message: String, image: UIImage?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 74 | 
                + var config = Config()  | 
            |
| 75 | 
                + config.toastType = .imageWithText(image, message)  | 
            |
| 76 | 
                + show(config: config, in: view)  | 
            |
| 77 | 
                + }  | 
            |
| 78 | 
                +  | 
            |
| 79 | 
                +    func showActivity(message: String?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 80 | 
                + var config = Config()  | 
            |
| 81 | 
                + config.toastType = .activityIndicator(message)  | 
            |
| 82 | 
                + show(config: config, in: view)  | 
            |
| 83 | 
                + }  | 
            |
| 84 | 
                +  | 
            |
| 67 | 85 | 
                     func hide() {
               | 
            
| 68 | 86 | 
                hideAnimation()  | 
            
| 69 | 87 | 
                }  | 
            
                @@ -101,6 +119,18 @@ public extension Toast {
               | 
            ||
| 101 | 119 | 
                globalInstance.show(message: message, in: view)  | 
            
| 102 | 120 | 
                }  | 
            
| 103 | 121 | 
                 | 
            
| 122 | 
                +    static func show(image: UIImage?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 123 | 
                + globalInstance.show(image: image, in: view)  | 
            |
| 124 | 
                + }  | 
            |
| 125 | 
                +  | 
            |
| 126 | 
                +    static func show(message: String, image: UIImage?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 127 | 
                + globalInstance.show(message: message, image: image, in: view)  | 
            |
| 128 | 
                + }  | 
            |
| 129 | 
                +  | 
            |
| 130 | 
                +    static func showActivity(message: String?, in view: UIView? = UIApplication.shared.keyWindow) {
               | 
            |
| 131 | 
                + globalInstance.showActivity(message: message, in: view)  | 
            |
| 132 | 
                + }  | 
            |
| 133 | 
                +  | 
            |
| 104 | 134 | 
                     static func hide() {
               | 
            
| 105 | 135 | 
                globalInstance.hide()  | 
            
| 106 | 136 | 
                }  | 
            
                @@ -11,6 +11,7 @@ import Foundation  | 
            ||
| 11 | 11 | 
                 public struct ToastOption {
               | 
            
| 12 | 12 | 
                var tintColor: UIColor = UIColor.white  | 
            
| 13 | 13 | 
                var backgroundColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)  | 
            
| 14 | 
                + var font: UIFont = UIFont.systemFont(ofSize: 14)  | 
            |
| 14 | 15 | 
                 | 
            
| 15 | 16 | 
                     public static var `default`: ToastOption {
               | 
            
| 16 | 17 | 
                return ToastOption()  | 
            
                @@ -8,33 +8,28 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 
                -class ToastView: UIView {
               | 
            |
| 11 | 
                +class ToastView: NiblessView {
               | 
            |
| 12 | 12 | 
                 | 
            
| 13 | 
                - fileprivate(set) var option: ToastOption  | 
            |
| 14 | 
                -    fileprivate(set) var toastType: Toast.ToastType = .text("")
               | 
            |
| 15 | 
                - fileprivate(set) var contentView: UIView = UIView()  | 
            |
| 13 | 
                + fileprivate var option: ToastOption  | 
            |
| 14 | 
                + fileprivate var toastType: Toast.ToastType  | 
            |
| 16 | 15 | 
                 | 
            
| 17 | 
                - fileprivate var _constraints: [NSLayoutConstraint] = []  | 
            |
| 16 | 
                + fileprivate var label: UILabel?  | 
            |
| 17 | 
                + fileprivate var imageView: UIImageView?  | 
            |
| 18 | 
                + fileprivate var activityIndicatorView: UIActivityIndicatorView?  | 
            |
| 18 | 19 | 
                 | 
            
| 19 | 
                -    override init(frame: CGRect) {
               | 
            |
| 20 | 
                - option = .default  | 
            |
| 21 | 
                - super.init(frame: CGRect.zero)  | 
            |
| 22 | 
                - }  | 
            |
| 20 | 
                + fileprivate var text: String?  | 
            |
| 21 | 
                + fileprivate var image: UIImage?  | 
            |
| 22 | 
                + fileprivate var isActivity: Bool = false  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                + fileprivate var topView: UIView?  | 
            |
| 25 | 
                + fileprivate var bottomView: UIView?  | 
            |
| 26 | 
                + fileprivate var padding = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)  | 
            |
| 23 | 27 | 
                 | 
            
| 24 | 
                -    required init?(coder aDecoder: NSCoder) {
               | 
            |
| 25 | 
                -        fatalError("init(coder:) has not been implemented")
               | 
            |
| 26 | 
                - }  | 
            |
| 27 | 28 | 
                 | 
            
| 28 | 
                -    convenience init(option: ToastOption, type: Toast.ToastType) {
               | 
            |
| 29 | 
                - self.init(frame: CGRect.zero)  | 
            |
| 29 | 
                +    init(option: ToastOption, type: Toast.ToastType) {
               | 
            |
| 30 | 30 | 
                self.option = option  | 
            
| 31 | 
                -  | 
            |
| 32 | 
                -        switch type {
               | 
            |
| 33 | 
                - case let .text(text):  | 
            |
| 34 | 
                - contentView = ToastTextView(text: text, option: option)  | 
            |
| 35 | 
                - default:  | 
            |
| 36 | 
                - break  | 
            |
| 37 | 
                - }  | 
            |
| 31 | 
                + self.toastType = type  | 
            |
| 32 | 
                + super.init(frame: CGRect.zero)  | 
            |
| 38 | 33 | 
                 | 
            
| 39 | 34 | 
                initProperty()  | 
            
| 40 | 35 | 
                }  | 
            
                @@ -47,50 +42,156 @@ class ToastView: UIView {
               | 
            ||
| 47 | 42 | 
                 | 
            
| 48 | 43 | 
                     override func didMoveToWindow() {
               | 
            
| 49 | 44 | 
                         switch toastType {
               | 
            
| 50 | 
                - case .text:  | 
            |
| 51 | 
                - constructViewHierarchyText()  | 
            |
| 52 | 
                - activateConstraintsText()  | 
            |
| 53 | 
                - default:  | 
            |
| 54 | 
                - break  | 
            |
| 45 | 
                + case let .text(t):  | 
            |
| 46 | 
                + text = t  | 
            |
| 47 | 
                + case let .image(i):  | 
            |
| 48 | 
                + image = i  | 
            |
| 49 | 
                + case let .imageWithText(i, t):  | 
            |
| 50 | 
                + image = i  | 
            |
| 51 | 
                + text = t  | 
            |
| 52 | 
                + case let .activityIndicator(t):  | 
            |
| 53 | 
                + text = t  | 
            |
| 54 | 
                + isActivity = true  | 
            |
| 55 | 55 | 
                }  | 
            
| 56 | 
                +  | 
            |
| 57 | 
                + constructViewHierarchy()  | 
            |
| 58 | 
                + activateConstraints()  | 
            |
| 56 | 59 | 
                }  | 
            
| 57 | 60 | 
                }  | 
            
| 58 | 61 | 
                 | 
            
| 59 | 
                -/// text  | 
            |
| 62 | 
                +/// construct view and layout  | 
            |
| 60 | 63 | 
                 fileprivate extension ToastView {
               | 
            
| 61 | 
                -    func constructViewHierarchyText() {
               | 
            |
| 62 | 
                - addSubview(contentView)  | 
            |
| 64 | 
                +  | 
            |
| 65 | 
                +    func constructViewHierarchy() {
               | 
            |
| 66 | 
                +        if image != nil {
               | 
            |
| 67 | 
                + imageView = makeImageView()  | 
            |
| 68 | 
                + addSubview(imageView!)  | 
            |
| 69 | 
                + }  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                +        if isActivity {
               | 
            |
| 72 | 
                + activityIndicatorView = makeActivityIndicatorView()  | 
            |
| 73 | 
                + addSubview(activityIndicatorView!)  | 
            |
| 74 | 
                + }  | 
            |
| 75 | 
                +  | 
            |
| 76 | 
                +        if text != nil {
               | 
            |
| 77 | 
                + label = makeLabel()  | 
            |
| 78 | 
                + addSubview(label!)  | 
            |
| 79 | 
                + }  | 
            |
| 80 | 
                + }  | 
            |
| 81 | 
                +  | 
            |
| 82 | 
                +    func activateConstraints() {
               | 
            |
| 83 | 
                + activateConstraintsImage()  | 
            |
| 84 | 
                + activateConstraintsIndicator()  | 
            |
| 85 | 
                + activateConstraintsText()  | 
            |
| 86 | 
                + activateConstraintsContentView()  | 
            |
| 87 | 
                + }  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                +    func activateConstraintsImage() {
               | 
            |
| 90 | 
                +        guard let imageView = imageView else { return }
               | 
            |
| 91 | 
                +  | 
            |
| 92 | 
                + imageView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 93 | 
                +  | 
            |
| 94 | 
                + NSLayoutConstraint.activate([  | 
            |
| 95 | 
                + imageView.widthAnchor.constraint(equalToConstant: 50),  | 
            |
| 96 | 
                + imageView.heightAnchor.constraint(equalToConstant: 50),  | 
            |
| 97 | 
                + imageView.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 98 | 
                + imageView.topAnchor.constraint(equalTo: topAnchor, constant: padding.top)  | 
            |
| 99 | 
                + ])  | 
            |
| 100 | 
                +  | 
            |
| 101 | 
                + topView = imageView  | 
            |
| 102 | 
                + }  | 
            |
| 103 | 
                +  | 
            |
| 104 | 
                +    func activateConstraintsIndicator() {
               | 
            |
| 105 | 
                +        guard let activityIndicatorView = activityIndicatorView else { return }
               | 
            |
| 106 | 
                +  | 
            |
| 107 | 
                + activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 108 | 
                +  | 
            |
| 109 | 
                + NSLayoutConstraint.activate([  | 
            |
| 110 | 
                + activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 111 | 
                + activityIndicatorView.topAnchor.constraint(equalTo: topAnchor, constant: padding.top)  | 
            |
| 112 | 
                + ])  | 
            |
| 113 | 
                +  | 
            |
| 114 | 
                + topView = activityIndicatorView  | 
            |
| 115 | 
                + activityIndicatorView.startAnimating()  | 
            |
| 63 | 116 | 
                }  | 
            
| 64 | 117 | 
                 | 
            
| 65 | 118 | 
                     func activateConstraintsText() {
               | 
            
| 66 | 
                - activateContraintsToastView()  | 
            |
| 67 | 
                - activateContraintsToastTextView()  | 
            |
| 119 | 
                +        guard let label = label else { return }
               | 
            |
| 120 | 
                +  | 
            |
| 121 | 
                + let windowSize = UIScreen.main.bounds.size  | 
            |
| 122 | 
                +  | 
            |
| 123 | 
                + label.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 124 | 
                +  | 
            |
| 125 | 
                + NSLayoutConstraint.activate([  | 
            |
| 126 | 
                + label.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 127 | 
                + widthAnchor.constraint(lessThanOrEqualToConstant: windowSize.width - 52),  | 
            |
| 128 | 
                + label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding.bottom),  | 
            |
| 129 | 
                + label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.left),  | 
            |
| 130 | 
                + label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding.right),  | 
            |
| 131 | 
                + label.topAnchor.constraint(equalTo: topView?.bottomAnchor ?? topAnchor, constant: 6),  | 
            |
| 132 | 
                + ])  | 
            |
| 133 | 
                +  | 
            |
| 134 | 
                +        if (text?.count ?? 0) <= 3 {
               | 
            |
| 135 | 
                +  | 
            |
| 136 | 
                +        } else {
               | 
            |
| 137 | 
                + NSLayoutConstraint.activate([  | 
            |
| 138 | 
                + ])  | 
            |
| 139 | 
                + }  | 
            |
| 140 | 
                +  | 
            |
| 141 | 
                +        if topView != nil {
               | 
            |
| 142 | 
                + NSLayoutConstraint.activate([  | 
            |
| 143 | 
                + label.widthAnchor.constraint(greaterThanOrEqualTo: heightAnchor)  | 
            |
| 144 | 
                + ])  | 
            |
| 145 | 
                + }  | 
            |
| 146 | 
                +  | 
            |
| 147 | 
                + bottomView = label  | 
            |
| 68 | 148 | 
                }  | 
            
| 69 | 149 | 
                 | 
            
| 70 | 
                -    func activateContraintsToastView() {
               | 
            |
| 150 | 
                +    func activateConstraintsContentView() {
               | 
            |
| 71 | 151 | 
                         guard let v = superview else { return }
               | 
            
| 72 | 152 | 
                translatesAutoresizingMaskIntoConstraints = false  | 
            
| 73 | 153 | 
                 | 
            
| 74 | 154 | 
                NSLayoutConstraint.activate([  | 
            
| 75 | 
                - contentView.centerXAnchor.constraint(equalTo: v.centerXAnchor),  | 
            |
| 76 | 
                - contentView.centerYAnchor.constraint(equalTo: v.centerYAnchor)  | 
            |
| 77 | 
                - ])  | 
            |
| 155 | 
                + centerXAnchor.constraint(equalTo: v.centerXAnchor),  | 
            |
| 156 | 
                + centerYAnchor.constraint(equalTo: v.centerYAnchor)  | 
            |
| 157 | 
                + ])  | 
            |
| 158 | 
                +  | 
            |
| 159 | 
                +        if topView == nil {
               | 
            |
| 160 | 
                + NSLayoutConstraint.activate([  | 
            |
| 161 | 
                + bottomView!.topAnchor.constraint(equalTo: topAnchor, constant: padding.top)  | 
            |
| 162 | 
                + ])  | 
            |
| 163 | 
                +        } else if bottomView == nil {
               | 
            |
| 164 | 
                + NSLayoutConstraint.activate([  | 
            |
| 165 | 
                + topView!.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding.bottom),  | 
            |
| 166 | 
                + topView!.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.left),  | 
            |
| 167 | 
                + topView!.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding.right)  | 
            |
| 168 | 
                + ])  | 
            |
| 169 | 
                + }  | 
            |
| 78 | 170 | 
                }  | 
            
| 79 | 
                -  | 
            |
| 80 | 
                -    func activateContraintsToastTextView() {
               | 
            |
| 81 | 
                - let windowSize = UIScreen.main.bounds.size  | 
            |
| 82 | 
                - contentView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 171 | 
                +}  | 
            |
| 172 | 
                +  | 
            |
| 173 | 
                +fileprivate extension ToastView {
               | 
            |
| 174 | 
                +    func makeLabel() -> UILabel {
               | 
            |
| 175 | 
                + let l = UILabel()  | 
            |
| 176 | 
                + l.text = text  | 
            |
| 177 | 
                + l.numberOfLines = 0  | 
            |
| 178 | 
                + l.font = option.font  | 
            |
| 179 | 
                + l.textAlignment = .center  | 
            |
| 180 | 
                + l.textColor = option.tintColor  | 
            |
| 83 | 181 | 
                 | 
            
| 84 | 
                - let textConstraints = [  | 
            |
| 85 | 
                - contentView.topAnchor.constraint(equalTo: topAnchor, constant: 6),  | 
            |
| 86 | 
                - contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -6),  | 
            |
| 87 | 
                - contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 6),  | 
            |
| 88 | 
                - contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -6),  | 
            |
| 89 | 
                - contentView.widthAnchor.constraint(lessThanOrEqualToConstant: windowSize.width - 40)  | 
            |
| 90 | 
                - ]  | 
            |
| 182 | 
                + return l  | 
            |
| 183 | 
                + }  | 
            |
| 184 | 
                +  | 
            |
| 185 | 
                +    func makeImageView() -> UIImageView {
               | 
            |
| 186 | 
                + let i = UIImageView()  | 
            |
| 187 | 
                + i.image = image  | 
            |
| 91 | 188 | 
                 | 
            
| 92 | 
                - NSLayoutConstraint.activate(textConstraints)  | 
            |
| 189 | 
                + return i  | 
            |
| 190 | 
                + }  | 
            |
| 191 | 
                +  | 
            |
| 192 | 
                +    func makeActivityIndicatorView() -> UIActivityIndicatorView {
               | 
            |
| 193 | 
                + let a = UIActivityIndicatorView(style: .white)  | 
            |
| 93 | 194 | 
                 | 
            
| 94 | 
                - _constraints += textConstraints  | 
            |
| 195 | 
                + return a  | 
            |
| 95 | 196 | 
                }  | 
            
| 96 | 197 | 
                }  | 
            
                @@ -9,7 +9,7 @@  | 
            ||
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 10 | 
                import WebKit  | 
            
| 11 | 11 | 
                 | 
            
| 12 | 
                -public class WebViewController: UIViewController {
               | 
            |
| 12 | 
                +public class WebViewController: NiblessViewController {
               | 
            |
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                public private(set) var path: String?  | 
            
| 15 | 15 | 
                 | 
            
                @@ -20,15 +20,11 @@ public class WebViewController: UIViewController {
               | 
            ||
| 20 | 20 | 
                }()  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                     public init(title: String, path: String) {
               | 
            
| 23 | 
                - super.init(nibName: nil, bundle: nil)  | 
            |
| 23 | 
                + super.init()  | 
            |
| 24 | 24 | 
                self.title = title  | 
            
| 25 | 25 | 
                self.path = path  | 
            
| 26 | 26 | 
                }  | 
            
| 27 | 27 | 
                 | 
            
| 28 | 
                -    required init?(coder aDecoder: NSCoder) {
               | 
            |
| 29 | 
                -        fatalError("init(coder:) has not been implemented")
               | 
            |
| 30 | 
                - }  | 
            |
| 31 | 
                -  | 
            |
| 32 | 28 | 
                     override public func viewDidLoad() {
               | 
            
| 33 | 29 | 
                super.viewDidLoad()  | 
            
| 34 | 30 | 
                view.backgroundColor = UIColor.white  | 
            
                @@ -6,14 +6,35 @@  | 
            ||
| 6 | 6 | 
                // Copyright © 2019 yb. All rights reserved.  | 
            
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                -import Foundation  | 
            |
| 9 | 
                +import UIKit  | 
            |
| 10 | 
                +import PaiaiDataKit  | 
            |
| 10 | 11 | 
                 | 
            
| 11 | 12 | 
                 class GroupCoordinator: Coordinator {
               | 
            
| 12 | 13 | 
                 | 
            
| 13 | 
                - var navigationController: UINavigationController  | 
            |
| 14 | 
                + let navigationController: UINavigationController  | 
            |
| 15 | 
                + let groupViewController: GroupViewController  | 
            |
| 14 | 16 | 
                 | 
            
| 15 | 
                -    init(navigationController: UINavigationController) {
               | 
            |
| 17 | 
                +    init(_ groupVC: GroupViewController, navigationController: UINavigationController) {
               | 
            |
| 18 | 
                + self.groupViewController = groupVC  | 
            |
| 16 | 19 | 
                self.navigationController = navigationController  | 
            
| 20 | 
                +  | 
            |
| 21 | 
                + groupViewController.viewModel.delegate = self  | 
            |
| 22 | 
                + }  | 
            |
| 23 | 
                +}  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +extension GroupCoordinator: GroupViewModelDelegate {
               | 
            |
| 26 | 
                +    func navigateToGroupDetail() {
               | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                + }  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                +    func didSelect(_ item: PhotoItem) {
               | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + }  | 
            |
| 33 | 
                +}  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +fileprivate extension GroupCoordinator {
               | 
            |
| 36 | 
                +    func makeGroupDetailViewController() {
               | 
            |
| 37 | 
                +  | 
            |
| 17 | 38 | 
                }  | 
            
| 18 | 39 | 
                }  | 
            
| 19 | 40 | 
                 | 
            
                @@ -1,10 +1,6 @@  | 
            ||
| 1 | 1 | 
                <?xml version="1.0" encoding="UTF-8"?>  | 
            
| 2 | 2 | 
                <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="s9X-RR-Rat">  | 
            
| 3 | 
                - <device id="retina4_7" orientation="portrait">  | 
            |
| 4 | 
                - <adaptation id="fullscreen"/>  | 
            |
| 5 | 
                - </device>  | 
            |
| 6 | 3 | 
                <dependencies>  | 
            
| 7 | 
                - <deployment identifier="iOS"/>  | 
            |
| 8 | 4 | 
                <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>  | 
            
| 9 | 5 | 
                <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>  | 
            
| 10 | 6 | 
                </dependencies>  | 
            
                @@ -101,10 +97,10 @@  | 
            ||
| 101 | 97 | 
                </objects>  | 
            
| 102 | 98 | 
                <point key="canvasLocation" x="-232" y="2161.6191904047978"/>  | 
            
| 103 | 99 | 
                </scene>  | 
            
| 104 | 
                - <!--GroupDetailController-->  | 
            |
| 100 | 
                + <!--GroupDetailViewController-->  | 
            |
| 105 | 101 | 
                <scene sceneID="Oa4-Yi-HJu">  | 
            
| 106 | 102 | 
                <objects>  | 
            
| 107 | 
                - <viewController storyboardIdentifier="GroupDetailController" id="s9X-RR-Rat" userLabel="GroupDetailController" customClass="GroupDetailController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 103 | 
                + <viewController storyboardIdentifier="GroupDetailViewController" id="s9X-RR-Rat" userLabel="GroupDetailViewController" customClass="GroupDetailViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">  | 
            |
| 108 | 104 | 
                <layoutGuides>  | 
            
| 109 | 105 | 
                <viewControllerLayoutGuide type="top" id="w38-w0-jLd"/>  | 
            
| 110 | 106 | 
                <viewControllerLayoutGuide type="bottom" id="a7q-m3-cDV"/>  | 
            
                @@ -420,7 +416,7 @@  | 
            ||
| 420 | 416 | 
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>  | 
            
| 421 | 417 | 
                <subviews>  | 
            
| 422 | 418 | 
                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="cas-Ep-jsP">  | 
            
| 423 | 
                - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>  | 
            |
| 419 | 
                + <rect key="frame" x="0.0" y="6" width="375" height="661"/>  | 
            |
| 424 | 420 | 
                <color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 425 | 421 | 
                <color key="separatorColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>  | 
            
| 426 | 422 | 
                <prototypes>  | 
            
                @@ -8,7 +8,17 @@  | 
            ||
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import Foundation  | 
            
| 10 | 10 | 
                 | 
            
| 11 | 
                -  | 
            |
| 11 | 
                +class GroupDetailCoordinator: Coordinator {
               | 
            |
| 12 | 
                + let navigationController: UINavigationController  | 
            |
| 13 | 
                + let groupDetailViewController: GroupDetailViewController  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +    init(_ groupDetailVC: GroupDetailViewController, navigationController: UINavigationController) {
               | 
            |
| 16 | 
                + self.groupDetailViewController = groupDetailVC  | 
            |
| 17 | 
                + self.navigationController = navigationController  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +// groupViewController.viewModel.delegate = self  | 
            |
| 20 | 
                + }  | 
            |
| 21 | 
                +}  | 
            |
| 12 | 22 | 
                 | 
            
| 13 | 23 | 
                 extension UIStoryboard {
               | 
            
| 14 | 24 | 
                     static var groupDetail: UIStoryboard {
               | 
            
                @@ -1,5 +1,5 @@  | 
            ||
| 1 | 1 | 
                //  | 
            
| 2 | 
                -// GroupDetailController.swift  | 
            |
| 2 | 
                +// GroupDetailViewController.swift  | 
            |
| 3 | 3 | 
                // PaiAi  | 
            
| 4 | 4 | 
                //  | 
            
| 5 | 5 | 
                // Created by zhengjianfei on 16/4/5.  | 
            
                @@ -12,7 +12,7 @@ import RxCocoa  | 
            ||
| 12 | 12 | 
                import PaiaiUIKit  | 
            
| 13 | 13 | 
                import PaiaiDataKit  | 
            
| 14 | 14 | 
                 | 
            
| 15 | 
                -final class GroupDetailController: UIViewController {
               | 
            |
| 15 | 
                +final class GroupDetailViewController: UIViewController {
               | 
            |
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                // MARK: Storyboard property  | 
            
| 18 | 18 | 
                @IBOutlet weak var scrollViewConstraint: NSLayoutConstraint!  | 
            
                @@ -7,15 +7,132 @@  | 
            ||
| 7 | 7 | 
                //  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                import UIKit  | 
            
| 10 | 
                +import PaiaiUIKit  | 
            |
| 10 | 11 | 
                 | 
            
| 11 | 
                -class GroupQRView: UIView {
               | 
            |
| 12 | 
                -  | 
            |
| 13 | 
                - /*  | 
            |
| 14 | 
                - // Only override draw() if you perform custom drawing.  | 
            |
| 15 | 
                - // An empty implementation adversely affects performance during animation.  | 
            |
| 16 | 
                -    override func draw(_ rect: CGRect) {
               | 
            |
| 17 | 
                - // Drawing code  | 
            |
| 12 | 
                +class GroupQRView: NiblessView {
               | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + private var groupName: String  | 
            |
| 15 | 
                + private var groupAvatar: String  | 
            |
| 16 | 
                + private var groupQR: String  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +    lazy var groupAvatarImageView: UIImageView = {
               | 
            |
| 19 | 
                + let imageView = UIImageView()  | 
            |
| 20 | 
                +  | 
            |
| 21 | 
                + imageView.image = UIImage(named: groupAvatar)  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                + return imageView  | 
            |
| 24 | 
                + }()  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +    lazy var groupNameLabel: UILabel = {
               | 
            |
| 27 | 
                + let label = UILabel()  | 
            |
| 28 | 
                +  | 
            |
| 29 | 
                + label.text = groupName  | 
            |
| 30 | 
                + label.font = UIFont.systemFont(ofSize: 17)  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + return label  | 
            |
| 33 | 
                + }()  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +    lazy var qrImageView: UIImageView = {
               | 
            |
| 36 | 
                + let imageView = UIImageView()  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + imageView.image = UIImage(qr: groupQR)  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                + return imageView  | 
            |
| 41 | 
                + }()  | 
            |
| 42 | 
                +  | 
            |
| 43 | 
                +    lazy var qrLabel: UILabel = {
               | 
            |
| 44 | 
                + let label = UILabel()  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                + label.text = "扫描二维码加入群"  | 
            |
| 47 | 
                + label.textColor = UIColor(gray: 153)  | 
            |
| 48 | 
                + label.font = UIFont.systemFont(ofSize: 14)  | 
            |
| 49 | 
                +  | 
            |
| 50 | 
                + return label  | 
            |
| 51 | 
                + }()  | 
            |
| 52 | 
                +  | 
            |
| 53 | 
                +    init(groupName: String, groupAvatar: String, groupQR: String) {
               | 
            |
| 54 | 
                + self.groupName = groupName  | 
            |
| 55 | 
                + self.groupAvatar = groupAvatar  | 
            |
| 56 | 
                + self.groupQR = groupQR  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + super.init(frame: CGRect.zero)  | 
            |
| 59 | 
                + }  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                +    override func didMoveToWindow() {
               | 
            |
| 62 | 
                + super.didMoveToWindow()  | 
            |
| 63 | 
                + constructViewHierarchy()  | 
            |
| 64 | 
                + activateConstraints()  | 
            |
| 65 | 
                + backgroundColor = UIColor.white  | 
            |
| 66 | 
                + }  | 
            |
| 67 | 
                +  | 
            |
| 68 | 
                +    private func constructViewHierarchy() {
               | 
            |
| 69 | 
                + addSubview(groupAvatarImageView)  | 
            |
| 70 | 
                + addSubview(groupNameLabel)  | 
            |
| 71 | 
                + addSubview(qrImageView)  | 
            |
| 72 | 
                + addSubview(qrLabel)  | 
            |
| 18 | 73 | 
                }  | 
            
| 19 | 
                - */  | 
            |
| 74 | 
                +}  | 
            |
| 20 | 75 | 
                 | 
            
| 76 | 
                +fileprivate extension GroupQRView {
               | 
            |
| 77 | 
                +    func activateConstraints() {
               | 
            |
| 78 | 
                + activateConstraintsContent()  | 
            |
| 79 | 
                + activateConstraintsQRImageView()  | 
            |
| 80 | 
                + activateConstraintsQRLabel()  | 
            |
| 81 | 
                + activateConstraintsGroupAvatarImageView()  | 
            |
| 82 | 
                + activateConstraintsGroupNameLabel()  | 
            |
| 83 | 
                + }  | 
            |
| 84 | 
                +  | 
            |
| 85 | 
                +    func activateConstraintsContent() {
               | 
            |
| 86 | 
                +        guard let superView = superview else { return }
               | 
            |
| 87 | 
                +  | 
            |
| 88 | 
                + translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                + NSLayoutConstraint.activate([  | 
            |
| 91 | 
                + widthAnchor.constraint(equalToConstant: 300),  | 
            |
| 92 | 
                + centerXAnchor.constraint(equalTo: superView.centerXAnchor),  | 
            |
| 93 | 
                + centerYAnchor.constraint(equalTo: superView.centerYAnchor)  | 
            |
| 94 | 
                + ])  | 
            |
| 95 | 
                + }  | 
            |
| 96 | 
                +  | 
            |
| 97 | 
                +    func activateConstraintsGroupAvatarImageView() {
               | 
            |
| 98 | 
                + groupAvatarImageView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                + NSLayoutConstraint.activate([  | 
            |
| 101 | 
                + groupAvatarImageView.widthAnchor.constraint(equalToConstant: 50),  | 
            |
| 102 | 
                + groupAvatarImageView.heightAnchor.constraint(equalToConstant: 50),  | 
            |
| 103 | 
                + groupAvatarImageView.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 104 | 
                + groupAvatarImageView.topAnchor.constraint(equalTo: topAnchor, constant: 12),  | 
            |
| 105 | 
                + ])  | 
            |
| 106 | 
                + }  | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                +    func activateConstraintsGroupNameLabel() {
               | 
            |
| 109 | 
                + groupNameLabel.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 110 | 
                +  | 
            |
| 111 | 
                + NSLayoutConstraint.activate([  | 
            |
| 112 | 
                + groupNameLabel.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 113 | 
                + groupNameLabel.topAnchor.constraint(equalTo: groupAvatarImageView.bottomAnchor, constant: 6)  | 
            |
| 114 | 
                + ])  | 
            |
| 115 | 
                +  | 
            |
| 116 | 
                + }  | 
            |
| 117 | 
                +  | 
            |
| 118 | 
                +    func activateConstraintsQRImageView() {
               | 
            |
| 119 | 
                + qrImageView.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 120 | 
                +  | 
            |
| 121 | 
                + NSLayoutConstraint.activate([  | 
            |
| 122 | 
                + qrImageView.widthAnchor.constraint(equalToConstant: 250),  | 
            |
| 123 | 
                + qrImageView.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 124 | 
                + qrImageView.widthAnchor.constraint(equalTo: qrImageView.heightAnchor),  | 
            |
| 125 | 
                + qrImageView.topAnchor.constraint(equalTo: groupNameLabel.bottomAnchor, constant: 12),  | 
            |
| 126 | 
                + ])  | 
            |
| 127 | 
                + }  | 
            |
| 128 | 
                +  | 
            |
| 129 | 
                +    func activateConstraintsQRLabel() {
               | 
            |
| 130 | 
                + qrLabel.translatesAutoresizingMaskIntoConstraints = false  | 
            |
| 131 | 
                +  | 
            |
| 132 | 
                + NSLayoutConstraint.activate([  | 
            |
| 133 | 
                + qrLabel.centerXAnchor.constraint(equalTo: centerXAnchor),  | 
            |
| 134 | 
                + qrLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12),  | 
            |
| 135 | 
                + qrLabel.topAnchor.constraint(equalTo: qrImageView.bottomAnchor, constant: 6),  | 
            |
| 136 | 
                + ])  | 
            |
| 137 | 
                + }  | 
            |
| 21 | 138 | 
                }  | 
            
                @@ -37,7 +37,7 @@ final class GroupViewController: UIViewController {
               | 
            ||
| 37 | 37 | 
                 | 
            
| 38 | 38 | 
                     var navigationBarViewImage: UIImageView = {
               | 
            
| 39 | 39 | 
                let image = UIImageView()  | 
            
| 40 | 
                - image.cornerRadius = 20  | 
            |
| 40 | 
                + image.cornerRadius = 18  | 
            |
| 41 | 41 | 
                return image  | 
            
| 42 | 42 | 
                }()  | 
            
| 43 | 43 | 
                 | 
            
                @@ -70,6 +70,7 @@ final class GroupViewController: UIViewController {
               | 
            ||
| 70 | 70 | 
                [unowned self] in  | 
            
| 71 | 71 | 
                self.viewModel.reload()  | 
            
| 72 | 72 | 
                }  | 
            
| 73 | 
                + collectionView.startRefreshing(at: .top)  | 
            |
| 73 | 74 | 
                }  | 
            
| 74 | 75 | 
                }  | 
            
| 75 | 76 | 
                 | 
            
                @@ -86,7 +87,6 @@ fileprivate extension GroupViewController {
               | 
            ||
| 86 | 87 | 
                }  | 
            
| 87 | 88 | 
                 | 
            
| 88 | 89 | 
                     func binding() {
               | 
            
| 89 | 
                - bindInteraction()  | 
            |
| 90 | 90 | 
                bindViewModelToRefreshing()  | 
            
| 91 | 91 | 
                bindCollectionViewDelegate()  | 
            
| 92 | 92 | 
                bindViewModelToCollectionView()  | 
            
                @@ -95,10 +95,6 @@ fileprivate extension GroupViewController {
               | 
            ||
| 95 | 95 | 
                bindViewModelToNavigationBarTitle()  | 
            
| 96 | 96 | 
                }  | 
            
| 97 | 97 | 
                 | 
            
| 98 | 
                -    func bindInteraction() {
               | 
            |
| 99 | 
                - photographBtn.rx.tap.bind(to: viewModel.photographBtnTapped).disposed(by: disposeBag)  | 
            |
| 100 | 
                - }  | 
            |
| 101 | 
                -  | 
            |
| 102 | 98 | 
                     func bindViewModelToRefreshing() {
               | 
            
| 103 | 99 | 
                viewModel.isLoading  | 
            
| 104 | 100 | 
                             .subscribe(onNext: {[unowned self] flag in
               | 
            
                @@ -156,15 +152,23 @@ extension GroupViewController: NavigationBarInteractiveViewController {
               | 
            ||
| 156 | 152 | 
                     private func setRightBarButtonItems() {
               | 
            
| 157 | 153 | 
                let item = UIBarButtonItem(images: [UIImage(named: "navigation-QR"),  | 
            
| 158 | 154 | 
                UIImage(named: "navigation-right")],  | 
            
| 159 | 
                - btnSpace: 6,  | 
            |
| 160 | 
                - target: self,  | 
            |
| 161 | 
                - actions: [#selector(viewModel!.presentGroupQR),  | 
            |
| 162 | 
                - #selector(viewModel!.navigateToGroupDetail)])  | 
            |
| 155 | 
                + targets: [self, viewModel],  | 
            |
| 156 | 
                + actions: [#selector(GroupViewController.presentGroupQR),  | 
            |
| 157 | 
                + #selector(GroupViewModel.navigateToGroupDetail)])  | 
            |
| 158 | 
                +  | 
            |
| 163 | 159 | 
                navigationItem.rightBarButtonItem = item  | 
            
| 164 | 160 | 
                }  | 
            
| 161 | 
                +  | 
            |
| 162 | 
                +    @objc func presentGroupQR() {
               | 
            |
| 163 | 
                + let alert = AlertViewController(style: .custom(GroupQRView(groupName: groupItem.group_name,  | 
            |
| 164 | 
                + groupAvatar: "Group\(groupItem.group_default_avatar)",  | 
            |
| 165 | 
                + groupQR: "https:pai.ai/g/\(groupItem.group_id)"),  | 
            |
| 166 | 
                + AlertAnimator()) )  | 
            |
| 167 | 
                + presentController(alert)  | 
            |
| 168 | 
                + }  | 
            |
| 165 | 169 | 
                }  | 
            
| 166 | 170 | 
                 | 
            
| 167 | 
                -/// layout  | 
            |
| 171 | 
                +/// navigation bar layout  | 
            |
| 168 | 172 | 
                 fileprivate extension GroupViewController {
               | 
            
| 169 | 173 | 
                 | 
            
| 170 | 174 | 
                     func activateConstraintsNavigation() {
               | 
            
                @@ -199,14 +203,18 @@ fileprivate extension GroupViewController {
               | 
            ||
| 199 | 203 | 
                navigationBarViewImage.translatesAutoresizingMaskIntoConstraints = false  | 
            
| 200 | 204 | 
                 | 
            
| 201 | 205 | 
                NSLayoutConstraint.activate([  | 
            
| 202 | 
                - navigationBarViewImage.widthAnchor.constraint(equalToConstant: 40),  | 
            |
| 203 | 
                - navigationBarViewImage.heightAnchor.constraint(equalToConstant: 40),  | 
            |
| 206 | 
                + navigationBarViewImage.widthAnchor.constraint(equalToConstant: 36),  | 
            |
| 207 | 
                + navigationBarViewImage.heightAnchor.constraint(equalToConstant: 36),  | 
            |
| 204 | 208 | 
                navigationBarViewImage.centerYAnchor.constraint(equalTo: navigationBarView.centerYAnchor),  | 
            
| 205 | 209 | 
                navigationBarViewImage.leadingAnchor.constraint(equalTo: navigationBarView.leadingAnchor),  | 
            
| 206 | 210 | 
                ])  | 
            
| 207 | 211 | 
                }  | 
            
| 208 | 212 | 
                }  | 
            
| 209 | 213 | 
                 | 
            
| 214 | 
                +extension GroupViewController {
               | 
            |
| 215 | 
                +  | 
            |
| 216 | 
                +}  | 
            |
| 217 | 
                +  | 
            |
| 210 | 218 | 
                 extension GroupViewController: UICollectionViewDelegateFlowLayout {
               | 
            
| 211 | 219 | 
                func collectionView(_ collectionView: UICollectionView,  | 
            
| 212 | 220 | 
                layout collectionViewLayout: UICollectionViewLayout,  | 
            
                @@ -231,10 +239,10 @@ extension GroupViewController: UIImagePickerControllerDelegate, UINavigationCont  | 
            ||
| 231 | 239 | 
                 | 
            
| 232 | 240 | 
                     func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
               | 
            
| 233 | 241 | 
                dismiss(animated: true, completion: nil)  | 
            
| 242 | 
                + guard let image = info[.originalImage] as? UIImage,  | 
            |
| 243 | 
                +            let data = image.scaledImage(length: 1280, with: 0.4) else { return }
               | 
            |
| 234 | 244 | 
                 | 
            
| 235 | 
                -        guard let image = info[.originalImage] as? UIImage else { return }
               | 
            |
| 236 | 
                -  | 
            |
| 237 | 
                - viewModel.submit(image: image)  | 
            |
| 245 | 
                + viewModel.submit(data: data)  | 
            |
| 238 | 246 | 
                }  | 
            
| 239 | 247 | 
                 | 
            
| 240 | 248 | 
                     func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
               | 
            
                @@ -24,7 +24,7 @@ final class ScanQRViewController: UIViewController {
               | 
            ||
| 24 | 24 | 
                // MARK: view function  | 
            
| 25 | 25 | 
                     override func viewDidLoad() {
               | 
            
| 26 | 26 | 
                super.viewDidLoad()  | 
            
| 27 | 
                - navigationController?.navigationBar.setBackgroundImage(UIImage.imageWithColor(UIColor.black), for: .default)  | 
            |
| 27 | 
                +// navigationController?.navigationBar.setBackgroundImage(UIImage.imageWithColor(UIColor.black), for: .default)  | 
            |
| 28 | 28 | 
                scanView.delegate = self  | 
            
| 29 | 29 | 
                }  | 
            
| 30 | 30 | 
                 | 
            
                @@ -60,11 +60,10 @@ extension MineCoordinator: MineViewControllerDelegate {
               | 
            ||
| 60 | 60 | 
                 | 
            
| 61 | 61 | 
                 extension MineCoordinator: MineGroupViewModelDelegate {
               | 
            
| 62 | 62 | 
                     func didSelect(_ item: GroupItem) {
               | 
            
| 63 | 
                - let vc = makeGroupViewController(item: item)  | 
            |
| 64 | 
                - let coordinator = GroupCoordinator(navigationController: navigationController)  | 
            |
| 63 | 
                + let coordinator = GroupCoordinator(makeGroupViewController(item: item),  | 
            |
| 64 | 
                + navigationController: navigationController)  | 
            |
| 65 | 65 | 
                childCoordinator["group"] = coordinator  | 
            
| 66 | 
                -  | 
            |
| 67 | 
                - navigationController.pushViewController(vc)  | 
            |
| 66 | 
                + navigationController.pushViewController(coordinator.groupViewController)  | 
            |
| 68 | 67 | 
                }  | 
            
| 69 | 68 | 
                }  | 
            
| 70 | 69 | 
                 | 
            
                @@ -82,7 +82,7 @@ extension MineViewController: UITableViewDataSource {
               | 
            ||
| 82 | 82 | 
                     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
               | 
            
| 83 | 83 | 
                let cell = tableView.dequeueReusableCell(withIdentifier: "mineCell", for: indexPath)  | 
            
| 84 | 84 | 
                cell.textLabel?.text = menuTitle[indexPath.row]  | 
            
| 85 | 
                - cell.textLabel?.textColor = UIColor(r: 51, g: 51, b: 51, a: 1.0)  | 
            |
| 85 | 
                + cell.textLabel?.textColor = UIColor(gray: 51)  | 
            |
| 86 | 86 | 
                cell.imageView?.image = UIImage(named: menuImage[indexPath.row])  | 
            
| 87 | 87 | 
                 | 
            
| 88 | 88 | 
                return cell  | 
            
                @@ -19,7 +19,7 @@ final class ImageCell: UICollectionViewCell, UIScrollViewDelegate {
               | 
            ||
| 19 | 19 | 
                photoImage.contentMode = .scaleAspectFit  | 
            
| 20 | 20 | 
                scrollView.contentSize = size  | 
            
| 21 | 21 | 
                scrollView.addSubview(photoImage)  | 
            
| 22 | 
                - photoImage.image = UIImage.imageWithColor(UIColor.black)  | 
            |
| 22 | 
                +// photoImage.image = UIImage.imageWithColor(UIColor.black)  | 
            |
| 23 | 23 | 
                         if !url.isEmpty {
               | 
            
| 24 | 24 | 
                // photoImage.setImageWithNullableURL(url, placeholderImage: UIImage(named: "详情页占位图"))  | 
            
| 25 | 25 | 
                         } else {
               |